﻿using System;

namespace Core.Shared.Monads
{
	public static class MaybeExtensions {
		public static TResult With<TInput, TResult>(this TInput o, Func<TInput, TResult> expression)
			where TInput : class
			where TResult : class {
			return o == null ? null : expression(o);
		}

		public static TInput If<TInput>(this TInput o, Func<TInput, bool> evaluator) where TInput : class {
			if (o == null) {
				return null;
			}
			return evaluator(o) ? o : null;
		}

		public static TInput Unless<TInput>(this TInput o, Func<TInput, bool> evaluator)
			where TInput : class {
			if (o == null) {
				return null;
			}
			return evaluator(o) ? null : o;
		}

		public static TInput Do<TInput>(this TInput o, Action<TInput> action) where TInput : class {
			if (o == null) {
				return null;
			}
			action(o);
			return o;
		}

		public static TResult Return<TInput, TResult>(this TInput o, Func<TInput, TResult> evaluator, TResult failureValue)
			where TInput : class {
			if (o == null) {
				return failureValue;
			}
			return evaluator(o);
		}

		public static bool ReturnSuccess<TInput>(this TInput o) where TInput : class {
			return o != null;
		}

		public static TResult WithException<TInput, TResult>(this TInput o, Func<TInput, TResult> evaluator)
			where TInput : class
			where TResult : class {
			return WithException(o, evaluator, new Exception());
		}

		public static TResult WithException<TInput, TResult, TException>(this TInput o, Func<TInput, TResult> evaluator, TException exception)
			where TInput : class
			where TResult : class
			where TException : Exception {
			TResult value;
			try {
				value = evaluator(o);
			} catch (TException) {
				return null;
			}

			return value;
		}
	}
}